<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>B站游戏区视频数据分析</title>
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
    <style>
        body {
            font-family: "Microsoft YaHei", sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
        }
        
        #chart-container {
            width: 95%;
            max-width: 1400px;
            height: 750px;
            margin: 0 auto;
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
            padding: 20px;
            box-sizing: border-box;
        }
        
        .header {
            text-align: center;
            margin-bottom: 15px;
        }
        
        .header h1 {
            color: #333;
            margin-bottom: 5px;
        }
        
        .header p {
            color: #666;
            margin-top: 0;
        }
        
        #chart {
            width: 100%;
            height: calc(100% - 40px);
        }
        
        .loading {
            text-align: center;
            padding-top: 50px;
            color: #666;
            font-size: 18px;
        }
        
        .chart-controls {
            text-align: center;
            margin-bottom: 15px;
        }
        
        .chart-btn {
            padding: 8px 15px;
            margin: 0 5px;
            background-color: #f0f0f0;
            border: 1px solid #ddd;
            border-radius: 4px;
            cursor: pointer;
            transition: all 0.3s;
        }
        
        .chart-btn.active {
            background-color: #58D9F9;
            color: white;
            border-color: #58D9F9;
        }
        
        @media (max-width: 768px) {
            #chart-container {
                height: 600px;
                padding: 10px;
            }
            
            .chart-btn {
                padding: 6px 10px;
                margin: 3px;
                font-size: 14px;
            }
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>B站游戏区视频数据分析</h1>
        <p>展示视频互动数据排行（鼠标悬停查看详情）</p>
    </div>
    
    <div class="chart-controls">
        <button class="chart-btn active" data-type="likeRate">点赞率排行</button>
        <button class="chart-btn" data-type="coinRate">投币率排行</button>
        <button class="chart-btn" data-type="favoriteRate">收藏率排行</button>
        <button class="chart-btn" data-type="shareCount">转发数排行</button>
    </div>
    
    <div id="chart-container">
        <div id="chart">
            <div class="loading">正在加载数据...</div>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 获取DOM元素引用
            const chartDom = document.getElementById('chart');
            const loadingElement = chartDom.querySelector('.loading');
            const chartButtons = document.querySelectorAll('.chart-btn');
            const myChart = echarts.init(chartDom);
            
            // 存储处理后的数据
            let processedData = [];
            
            // 图表配置常量
            const CHART_CONFIG = {
                likeRate: { name: '点赞率排行', unit: '%', formatter: '{c}%' },
                coinRate: { name: '投币率排行', unit: '%', formatter: '{c}%' },
                favoriteRate: { name: '收藏率排行', unit: '%', formatter: '{c}%' },
                shareCount: { name: '转发数排行', unit: '次', formatter: '{c}' }
            };
            
            // 初始化应用
            initApplication();
            
            /**
             * 初始化应用
             */
            function initApplication() {
                loadData();
                setupEventListeners();
            }
            
            /**
             * 设置事件监听器
             */
            function setupEventListeners() {
                // 图表切换按钮事件
                chartButtons.forEach(btn => {
                    btn.addEventListener('click', handleChartButtonClick);
                });
                
                // 窗口大小改变时重新调整图表大小
                window.addEventListener('resize', () => myChart.resize());
            }
            
            /**
             * 处理图表按钮点击事件
             */
            function handleChartButtonClick() {
                // 更新按钮状态
                chartButtons.forEach(b => b.classList.remove('active'));
                this.classList.add('active');
                
                // 渲染对应图表
                renderChart(this.dataset.type);
            }
            
            /**
             * 加载JSON数据
             */
            function loadData() {
                fetch('../static/game.json')
                    .then(handleFetchResponse)
                    .then(processRawData)
                    .then(data => {
                        processedData = data;
                        renderChart('likeRate');
                        loadingElement.style.display = 'none';
                    })
                    .catch(handleFetchError);
            }
            
            /**
             * 处理fetch响应
             */
            function handleFetchResponse(response) {
                if (!response.ok) {
                    throw new Error('网络响应不正常');
                }
                return response.json();
            }
            
            /**
             * 处理fetch错误
             */
            function handleFetchError(error) {
                console.error('加载数据失败:', error);
                loadingElement.innerHTML = `
                    <div style="color:#f56c6c;">
                        <h3>数据加载失败</h3>
                        <p>${error.message}</p>
                        <p>请检查JSON文件路径是否正确</p>
                    </div>
                `;
            }
            
            /**
             * 处理原始数据
             * 1. 数据去重
             * 2. 计算各种比率
             * 3. 格式化标题
             */
            function processRawData(rawData) {
                const uniqueMap = new Map();
                
                // 数据去重处理
                rawData.forEach(item => {
                    let bvid = item.bvid || '';
                    if (!bvid && item.video_url) {
                        const match = item.video_url.match(/\/video\/(BV\w+)/);
                        bvid = match ? match[1] : '';
                    }
                    
                    const key = bvid || item.title;
                    if (!uniqueMap.has(key)) {
                        item.bvid = bvid;
                        uniqueMap.set(key, item);
                    }
                });
                
                // 计算比率和格式化
                return Array.from(uniqueMap.values()).map(item => {
                    const views = Math.max(1, parseInt(item.views));
                    
                    // 计算各项比率
                    const likeRate = (parseInt(item.like) / views * 100).toFixed(2);
                    const coinRate = (parseInt(item.coin) / views * 100).toFixed(2);
                    const favoriteRate = (parseInt(item.favorite) / views * 100).toFixed(2);
                    const shareCount = parseInt(item.share);
                    
                    // 格式化标题
                    const displayTitle = formatTitle(item.title);
                    
                    return {
                        name: displayTitle.short,
                        fullTitle: displayTitle.full,
                        likeRate: parseFloat(likeRate),
                        coinRate: parseFloat(coinRate),
                        favoriteRate: parseFloat(favoriteRate),
                        shareCount: shareCount,
                        raw: {
                            bvid: item.bvid,
                            views: item.views,
                            likes: item.like,
                            coins: item.coin,
                            favorites: item.favorite,
                            shares: item.share,
                            danmu: item.danmu,
                            author: item.up_name,
                            pubdate: item.pubdate,
                            url: item.video_url
                        }
                    };
                });
            }
            
            /**
             * 格式化视频标题
             * 1. 移除括号内容
             * 2. 缩短长标题并添加省略号
             */
            function formatTitle(title) {
                // 移除【】和[]中的内容
                let cleanedTitle = title.replace(/【.*?】|\[.*?\]/g, '').trim();
                
                // 处理长标题
                if (cleanedTitle.length > 15) {
                    return {
                        short: cleanedTitle.substring(0, 12) + '...',
                        full: title
                    };
                }
                
                return {
                    short: cleanedTitle,
                    full: title
                };
            }
            
            /**
             * 渲染图表
             * @param {string} chartType - 图表类型 (likeRate, coinRate, favoriteRate, shareCount)
             */
            function renderChart(chartType) {
                if (!processedData.length) return;
                
                // 获取图表配置
                const { name: chartName, unit, formatter } = CHART_CONFIG[chartType];
                
                // 根据图表类型排序数据
                const sortedData = sortDataByType(processedData, chartType);
                
                // 生成ECharts配置项
                const option = generateChartOption(chartType, sortedData, chartName, unit, formatter);
                
                // 设置图表选项
                myChart.setOption(option, true);
            }
            
            /**
             * 根据图表类型排序数据
             */
            function sortDataByType(data, type) {
                switch(type) {
                    case 'coinRate':
                        return [...data].sort((a, b) => b.coinRate - a.coinRate);
                    case 'favoriteRate':
                        return [...data].sort((a, b) => b.favoriteRate - a.favoriteRate);
                    case 'shareCount':
                        return [...data].sort((a, b) => b.shareCount - a.shareCount);
                    default: // likeRate
                        return [...data].sort((a, b) => b.likeRate - a.likeRate);
                }
            }
            
            /**
             * 生成ECharts图表配置项
             */
            function generateChartOption(chartType, sortedData, chartName, unit, formatter) {
                return {
                    title: {
                        text: chartName,
                        left: 'center',
                        textStyle: { fontSize: 16, color: '#333' }
                    },
                    tooltip: {
                        trigger: 'item',
                        backgroundColor: 'rgba(50, 50, 50, 0.95)',
                        borderColor: '#555',
                        borderWidth: 1,
                        padding: [10, 15],
                        textStyle: { color: '#fff', fontSize: 14 },
                        formatter: function(params) {
                            return generateTooltipContent(params, sortedData, chartName, unit);
                        }
                    },
                    grid: {
                        top: '15%',
                        right: '3%',
                        bottom: '22%',
                        left: '8%'
                    },
                    xAxis: {
                        type: 'category',
                        data: sortedData.map(d => d.name),
                        axisLabel: {
                            rotate: 45,
                            interval: 0,
                            fontSize: 12,
                            color: '#666',
                            margin: 20,
                            verticalAlign: 'middle',
                            overflow: 'truncate',
                            width: 80
                        },
                        axisTick: { alignWithLabel: true, length: 6, lineStyle: { color: '#ccc' } },
                        axisLine: { lineStyle: { color: '#aaa', width: 1.5 } },
                        splitArea: { show: false }
                    },
                    yAxis: {
                        type: 'value',
                        name: chartName.split('排行')[0] + (unit === '%' ? ' (%)' : ' (次)'),
                        nameTextStyle: { padding: [0, 0, 0, 40], color: '#666' },
                        axisLabel: { formatter: unit === '%' ? '{value}%' : '{value}', color: '#666' },
                        splitLine: { lineStyle: { type: 'dashed', color: '#eee' } },
                        axisLine: { show: true, lineStyle: { color: '#aaa' } }
                    },
                    series: [{
                        name: chartName.split('排行')[0],
                        type: 'bar',
                        data: sortedData.map(d => d[chartType === 'shareCount' ? 'shareCount' : `${chartType}`]),
                        barWidth: '60%',
                        itemStyle: {
                            color: function(params) {
                                return getBarColor(params.value, chartType);
                            },
                            borderRadius: [4, 4, 0, 0]
                        },
                        label: {
                            show: true,
                            position: 'top',
                            formatter: formatter,
                            color: '#666',
                            fontSize: 12
                        },
                        emphasis: {
                            itemStyle: {
                                shadowBlur: 10,
                                shadowColor: 'rgba(0, 0, 0, 0.3)'
                            }
                        }
                    }],
                    dataZoom: [{
                        type: 'slider',
                        show: true,
                        xAxisIndex: 0,
                        start: 0,
                        end: 100,
                        bottom: '8%',
                        height: 18,
                        handleSize: '80%',
                        handleStyle: { color: '#8392A5' },
                        textStyle: { color: '#666' }
                    }],
                    animation: true,
                    animationDuration: 1000,
                    animationEasing: 'cubicOut'
                };
            }
            
            /**
             * 根据数值和图表类型获取条形图颜色
             */
            function getBarColor(value, chartType) {
                if (chartType === 'shareCount') {
                    return value > 100 ? '#FF6E76' :
                           value > 50 ? '#FDDD60' : '#58D9F9';
                } else {
                    return value > 10 ? '#FF6E76' :
                           value > 5 ? '#FDDD60' : '#58D9F9';
                }
            }
            
            /**
             * 生成工具提示内容
             */
            function generateTooltipContent(params, sortedData, chartName, unit) {
                const dataItem = sortedData[params.dataIndex];
                const videoId = dataItem.raw.bvid
                    ? `BV号: ${dataItem.raw.bvid}`
                    : `视频URL: ${dataItem.raw.url || '无'}`;
                
                const valueKey = chartName.includes('点赞') ? 'likeRate' :
                                chartName.includes('投币') ? 'coinRate' :
                                chartName.includes('收藏') ? 'favoriteRate' : 'shareCount';
                
                return `
                    <div style="margin-bottom:8px;font-size:16px;font-weight:bold;color:#FFD700">
                        ${dataItem.fullTitle}
                    </div>
                    <div style="margin-bottom:5px">
                        <span style="display:inline-block;width:60px">UP主:</span>
                        ${dataItem.raw.author || '未知'}
                    </div>
                    <div style="margin-bottom:5px">
                        ${videoId}
                    </div>
                    <div style="border-top:1px dashed #666;padding-top:8px;margin-top:8px">
                        <span style="color:#FF6E76">${chartName.split('排行')[0]}: ${dataItem[valueKey]}${unit}</span><br>
                        播放: ${dataItem.raw.views} |
                        点赞: ${dataItem.raw.likes} |
                        投币: ${dataItem.raw.coins} |
                        收藏: ${dataItem.raw.favorites} |
                        转发: ${dataItem.raw.shares} |
                        弹幕: ${dataItem.raw.danmu}
                    </div>
                `;
            }
        });
    </script>
</body>
</html>
